package com.utrans.web;

import com.utrans.entity.Estacion;
import com.utrans.web.util.JsfUtil;
import com.utrans.web.util.PaginationHelper;
import com.utrans.ejb.EstacionFacade;

import java.io.Serializable;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

@ManagedBean(name = "estacionController")
@SessionScoped
public class EstacionController implements Serializable {

    private Estacion current;
    private DataModel items = null;
    private DataModel estacionesRecorridoRuta= null;
    private boolean inicioBusqueda;
    private int codeRutaBusqueda;
    private int caso;
    private String paginasGestiones[]={"Edit", "Estado", "RutasEstacion", "View"};
    private String paginasPreGestiones[]={"PreEdit", "PreEstado", "PreRutasEstacion", "Buscar"};
    @EJB
    private com.utrans.ejb.EstacionFacade ejbFacade;
    private PaginationHelper pagination;
    private int selectedItemIndex;

    public EstacionController() {
    }

    /**
     * @return Estacion seleccionada o gestionada actualmente
     */
    public Estacion getSelected() {
        if (current == null) {
            current = new Estacion();
            selectedItemIndex = -1;
        }
        return current;
    }

   
    /**
     * @return controlador ejbFacade de Persistencia de Estacion
     */
    private EstacionFacade getFacade() {
        return ejbFacade;
    }

    
    /**
     * Muestra una página con listado de maximo 20 Estaciones de dependiendo de 
     * la búsqueda realizada, la cual se determina de acuerdo al valor de caso:
     *      Si caso es 1: busca todas la estaciones
     *      Si es caso 2: busca una Estacion por su nombre o du código.
     *      Sino el caso es 3: busca las Rutas que pasan por la Estcaion acutal.
     * Retorna los resultados de la consulta en grupos de 20. 
     * @return Página con las 20 Estaciones encontradas en el rango solicitado.
     */
    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(20) {

                @Override
                public int getItemsCount() {
                    if (caso == 1)
                        return getFacade().count();
                    if (caso == 2)
                        return getFacade().countByNameCode(current.getNombreEstacion());
                    //caso =3
                    else
                        return getFacade().countEstacionesDeRuta(codeRutaBusqueda);
                }                
               

                @Override
                public DataModel createPageDataModel() {
                    if(caso == 1) {
                        return new ListDataModel(getFacade().findRange(new int[]{getPageFirstItem(),
                            getPageFirstItem() + getPageSize()})); 
                    }
                    if(caso == 2){
                        return new ListDataModel(getFacade().findRangeByNameCode                            
                            (new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}, current.getNombreEstacion()));
                    }
                    //Caso = 3
                    else{
                        return new ListDataModel(getFacade().estacionesDeRuta                          
                            (new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}, codeRutaBusqueda)); 
                    }
                }
            };
        }
        return pagination;
    }
    
    /**
     * Llama al método recreateModels, para vaciar la lista de Estaciones contenida
     * en la página List.xhml
     * @return Nombre de la página dónde se visualiza la lista
     */
    public String prepareList() {
        recreateModels();
        return "List";
    }
    
    /**
     * Llama al método recreateModels, para vaciar la lista que se encuentre 
     * en la página actual, esta puede ser: Buscar, List, PreEdit, PreEstado o
     * PreRutasEstacion. Asigna el valor false a inicioBusqueda para indicar que 
     * no se ha realizado ninguna busqueda..
     */
    public void prepareResultList() {
        recreateModels();
        inicioBusqueda = false;
    }  
    
    /**
     * Instancia a current, para que los campos en la página Create.xhtml estén 
     * vacíos cuando esta se cargue para crear una nueva Estacion. 
     * @return Nombre de la página en la que se pueden crear nuevas Estaciones
     */
    public String prepareCreate() {
        current = new Estacion();
        selectedItemIndex = -1;
        return "Create";
    }

    /**
     * Utiliza al controlador ejbFacade de Estacion para crear un nuevo registro de Estacion
     * en la base de datos.
     * @return El nombre de la página donde se puede ver la informacion de la 
     * Estacion creada.
     */
    public String create() {
        try {
            getFacade().create(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("EstacionCreated"));
            return "View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }    
    
    
    /**
     * Instancia a current y asigna el valor -1 a selectedItemIndex, para que en las 
     * paginas no se visualice información de ninguna Estacion. Indica que se ha 
     * iniciado una busqueda, limpia las listas que se hayan cargado.
     * @param indexPagina indice del nombre de la página en el arreglo paginasPreGestiones[]
     * @return Nombre de la página que depende de la gestion que se quiera realizar 
     * despues de la busqueda.
     */
    public String preparePreGestion(int indexPagina) {
        current = new Estacion();
        selectedItemIndex = -1;
        inicioBusqueda = true;
        recreateModels();
        pagination = null;
        return paginasPreGestiones[indexPagina];
    }
    
    /**
     * Asigna a current la Estacion seleccionada de una lista de Estaciones.
     * @param indexPagina indice del nombre de la página en el arreglo paginasGestiones[]
     * @return Nombre de la página que depende de la gestion que se quiera realizar.
     */
    public String prepareGestion(int indexPagina) {        
        current = (Estacion) items.getRowData();
        
        selectedItemIndex = pagination.getPageFirstItem() + items.getRowIndex();
        //Si indexPagina corresponde  al indice de "RutasEstacion"
        //if(indexPagina == 3)
            recreateModels();
        return paginasGestiones[indexPagina];
    }   
        
    /**
     * Utiliza al controlador ejbFacade de Estacion para guardar en la base de datos 
     * cualquier cambio ralizado a una Estacion.
     * @return El nombre de la página donde se puede ver la informacion de la 
     * Estacion modificada.
     */     
    public String update() {
        try {
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("EstacionUpdated"));
            return "View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    /**
     * Asigna a current la Estacion seleccionada de una lista, llama al método 
     * performDsetroy para eliminarla de la base de datos.
     * @return El nombre de la página donde se lsitan todas las Estaciones
     */ 
    public String destroy() {
        current = (Estacion) items.getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + items.getRowIndex();
        performDestroy();
        recreateModels();
        return "List";
    }

    /**
     * Asigna a current la Estacion seleccionada de una lista, llama al método 
     * performDsetroy para eliminarla de la base de datos.
     * @return El nombre de la página donde se puede ver la informacion de la 
     * Estacion eliminada.
     */ 
    public String destroyAndView() {
        performDestroy();
        recreateModels();
        updateCurrentItem();
        if (selectedItemIndex >= 0) {
            return "View";
        } else {
            // all items were removed - go back to list
            recreateModels();
            return "List";
        }
    }

    /**
     * Utiliza al controlador ejbFacade de Estacion para eliminar una Estacion en la base 
     * de datos.
     */ 
    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("EstacionDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void updateCurrentItem() {
        int count = getFacade().count();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count - 1;
            // go to previous page if last page disappeared:
            if (pagination.getPageFirstItem() >= count) {
                pagination.previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            current = getFacade().findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
        }
    }

    
    /**
     * Llama al método getPagination() para buscar las primeras 20 estaciones 
     * dependiendo de la consulta realizada por el usuario, cada caso se describe
     * en método getPagination()
     * @param c valor del caso
     * @return pagina con las 20 Estaciones
     */
    public DataModel getItems(int c) {
        if (items == null) {
            caso = c;
            items = getPagination().createPageDataModel();
        }
        return items;
    }
    
    /**
     * Llama al método getPagination() con el caso 3 para buscar las Estaciones que 
     * han sido asignadas a una Ruta. 
     * @param codeRuta codigo de la Ruta consultada.
     * @return Pagina con las Estaciones de dicha Ruta
     */
    public DataModel getEstacionesRecorridoRuta(int codeRuta) {
        codeRutaBusqueda=codeRuta;
        if (estacionesRecorridoRuta == null) {
            caso = 3;
            estacionesRecorridoRuta = getPagination().createPageDataModel();
        }
        return estacionesRecorridoRuta;
    }
    
    /**
     * @return El valor de inicioBusqueda, el cual vale true si el usario ha 
     * realizado una consulta de lo contario vale false.
     */
    public boolean getInicioBusqueda(){
        return inicioBusqueda;
    }
      
    /**
     * Limpia todas las listas.
     */
    private void recreateModels() {
        items = null;
        estacionesRecorridoRuta = null;
    }
    
    /**
     * Limpia la lista actual  y busca la lista con las 20 Estaciones siguientes. 
     * @return Nombre de la página donde se visualiza la Lista de Estaciones.
     */
    public String next() {
        recreateModels();
        caso = 1;
        getPagination().nextPage();        
        return "List";
    }

    /**
     * Limpia la lista actual  y busca la lista con las 20  Estaciones anteriores. 
     * @return Nombre de la página donde se visualiza la Lista de Estaciones.
     */
    public String previous() {
        recreateModels();
        caso = 1;
        getPagination().previousPage();
        return "List";
    }
        
    /**
     * Limpia la lista actual  y busca la lista con las 20  Estaciones siguientes.
     * @param indexPagina indice del nombre de la página en el arreglo paginasGestiones[]
     * @return Nombre de la página donde se visualiza la Lista de Estaciones 
     * producto de una consulta por nombre o código
     */
    public String nextPreGestionList(int indexPagina) {
        recreateModels();
        caso = 2;
        getPagination().nextPage();
        return paginasPreGestiones[indexPagina];
    }

    /**
     * Limpia la lista actual  y busca la lista con las 20  Estaciones anteriores.
     * @param indexPagina indice del nombre de la página en el arreglo paginasGestiones[]
     * @return Nombre de la página donde se visualiza la Lista de Estaciones 
     * producto de una consulta por nombre o código
     */
    public String previousPreGestionList(int indexPagina) {
        recreateModels();
        caso = 2;
        getPagination().previousPage();
        return paginasPreGestiones[indexPagina];
    } 
    
    /**
     * 
     * @return 
     */
    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll("nombreEstacion"), false);
    }

    
    /**
     * 
     * @return 
     */
    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll("nombreEstacion"), true);
    }

    /**
     * 
     */
    @FacesConverter(forClass = Estacion.class)
    public static class EstacionControllerConverter implements Converter {

        /**
         * 
         * @param facesContext
         * @param component
         * @param value
         * @return 
         */
        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            EstacionController controller = (EstacionController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "estacionController");
            return controller.ejbFacade.find(getKey(value));
        }

        /**
         * 
         * @param value
         * @return 
         */
        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        /**
         * 
         * @param value
         * @return 
         */
        String getStringKey(java.lang.Integer value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        /**
         * 
         * @param facesContext
         * @param component
         * @param object
         * @return 
         */
        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Estacion) {
                Estacion o = (Estacion) object;
                return getStringKey(o.getCodigoEstacion());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + EstacionController.class.getName());
            }
        }
    }
}
